package com.nixus.raop;

import java.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;

import javax.jmdns.ServiceListener;

import org.apache.http.conn.util.InetAddressUtils;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.ToggleButton;

import com.nixus.raop.core.PropertyManager;
import com.nixus.raop.core.ServiceContextImpl;
import com.nixus.raop.core.ServicesManager;
import com.nixus.raop.player.PlayerImpl;
import com.nixus.raop.speaker.airport.Finder;
import com.nixus.raop.speaker.airport.SpeakerImpl;
import com.nixus.raop.zeroconf.ZeroConfFactory;

public class RaopHelper extends Observable implements ServicesManager{
	
	
	public static Map<String,ServiceContextImpl> contexts;
	
	public static PropertyManager pm;

	protected ServiceListener listener;

	private List<NativeRaopTask> raopTasks = new ArrayList<NativeRaopTask>();
	private HashMap<String,Boolean> raopSwitches = new HashMap<String,Boolean>();
	
	public final static String HOST_NAME = "tsthostname";

	private PlayerImpl pl;

	//private LibraryAdapter discoveredDevicesAdapter;

	public RaopHelper(){
		super();
	}
	

	public void addServiceContext(final ServiceContextImpl context) {
		contexts.put(context.getProperty("host")==null?context.getServiceName():context.getProperty("host"),context);
		
		if (context.getService() instanceof SpeakerImpl){
//			new Thread( new Runnable() {
//				public void run() {
					setChanged();
					notifyObservers(context);
//				}
//			}).start();
		}
	}

	public void removeServiceContext(ServiceContextImpl context) {
//		contexts.remove(context);
//		pm.remove(context.getProperty("name"));
	}

	public Iterator<ServiceContextImpl> getServices() {
		return contexts.values().iterator();
	}
	
	void startDeviceDiscovery() {
		
		this.setChanged();
		notifyObservers("Starting discovery");
		
		contexts = new HashMap<String, ServiceContextImpl>();

		pm =  new PropertyManager();
		pm.init();

		ServiceContextImpl sczcf = new ServiceContextImpl(new ZeroConfFactory(), "zeroconffactory",pm,this);
		sczcf.putProperty("implementation", "jmdns");
		sczcf.putProperty("bind", getLocalIpAddress());
		sczcf.putProperty("hostname", HOST_NAME);
		this.addServiceContext(sczcf);
		sczcf.start();


		ServiceContextImpl scaf = new ServiceContextImpl(new Finder(), "airportfactory",pm,this);
		this.addServiceContext(scaf);
		scaf.start();

		pl = new PlayerImpl();
		ServiceContextImpl scpl = new ServiceContextImpl(pl, "main",pm,this);
		this.addServiceContext(scpl);
		scpl.start();
	}
	
	static void setRaopSwitch(String swtch) {
		FileWriter sfw;
		try {
			sfw = new FileWriter("/data/raop_switch");
			sfw.write(swtch);
			sfw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	static String getLocalIpAddress() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress() && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress())) {
						System.out.println("Found addr = " + inetAddress.getHostAddress().toString());
						return inetAddress.getHostAddress().toString();
					}
				}
			}
		} catch (SocketException ex) {
			Log.e("MainPage", ex.toString());
		}
		return null;
	}
	
	private class NativeRaopTask extends AsyncTask<String,String,String> {
		
		private ToggleButton tb;
		private String address;
		
		public NativeRaopTask(String address) {
			this.address =address;
		}
		
		protected void onPreExecute() {
//			 setRaopSwitch("1");
//	    	 System.out.println("Streaming PreExecute");
	    }
		@Override 
		protected String doInBackground(String... airportAddress) {
				raopSwitches.put((String) airportAddress[0], true);
				String[] args = new String[5];
				args[0] = "raop-play";
				args[1] = "--proto";
				args[2] = "tcp";
				args[3] = (String) airportAddress[0];
				args[4] = "socket://";
				int pid = raopPlay(args);
				System.out.println("Process exited " + pid);
				return null;
	     }
		 protected void onPostExecute() {
			 raopSwitches.put(address, false);
			 RaopHelper.setRaopSwitch("O");
			 tb.setSelected(false);
	    	 System.out.println("Streaming terminated");
	     }
	}

	public void startStreaming(String airportAddress) {
		System.out.println("Starting streaming on " + airportAddress);
		
		NativeRaopTask raop = new NativeRaopTask(airportAddress);
		raop.execute(airportAddress);
		raopTasks.add(raop);
		
		setChanged();
		notifyObservers("Streaming on " + getAirportName(airportAddress));

	}
	


	public void stopStreaming(String airportAddress) {
		setRaopSwitch("0"); 
		raopSwitches.put(airportAddress, false);

	}

	
	public String getAirportName(String airportAddress ){
		return contexts.get(airportAddress).getProperty("name").replace("speaker.airport.", "");
		
	}
	


	/* A native method that is implemented by the
	 * 'hello-jni' native library, which is packaged
	 * with this application.
	 */
	public native int raopPlay(String[] args);
	public static native void  nativePipeSTDERRToLogcat();

	static {
		System.loadLibrary("ssl");
		System.loadLibrary("crypto");
		System.loadLibrary("samplerate");
		System.loadLibrary("raop-play");
		new Thread() {
			public void run() {
				nativePipeSTDERRToLogcat();
			}
		}.start();
	}
	
	// sorry about these
	public String notify(String text) {
	    System.out.println("BBBBB" + text);
	    return text;
	}
	
	public boolean notifyAvailability(boolean available) {
	    System.out.println("JNI process ready for streaming " + available);
	    if (available)
	    	setRaopSwitch("1");
	    else
	    	setRaopSwitch("0");
	    		
	    return true;
	}
	
	public boolean isActivated(String address) {
	    System.out.println("isActivated " + address);
	    return raopSwitches.get(address).booleanValue();
	}

}
